from __future__ import with_statement

from collections import deque
import hashlib

import fs

default_hash_function = hashlib.sha512

class Job(object):
    def __init__(self, left_fs, right_fs) :
        self.left_fs = left_fs
        self.right_fs = right_fs
        self.action_queue = deque()
        self.hash_function = default_hash_function
        
    def do(self, verbose=False):
        action, left_path, right_path = self.action_list[0]
        action(left_path, right_path)
        self.action_queue.popleft()
            
    def _do_copy_left_to_right(self, path):
        if self.left_fs.isdir(path):
            fs.utils.copydir(self.left_fs.opendir(path), self.right_fs.makeopendir(path))
        else:
            fs.utils.copyfile(self.left_fs, path, self.right_fs, path)
        self._do_copy_time_left_to_right(path)
    
    def _do_copy_right_to_left(self, path):
        if self.left_fs.isdir(path):
            fs.utils.copydir(self.right_fs.opendir(path), self.left_fs.makeopendir(path))
        else:
            fs.utils.copyfile(self.right_fs, path, self.left_fs, path)
        self._do_copy_time_right_to_left(path)
    
    def _do_copy_time_left_to_right(self, path):
        pass
    
    def _do_copy_time_right_to_left(self, path):
        pass
    
    def _do_remove_left(self, path):
        if 
        pass
    
    def _do_remove_right(self, path):
        pass
    
    def _add_copy_left_to_right(self, path):
        self.action_queue.append((self._do_copy_left_to_right, path))
    
    def _add_copy_right_to_left(self, path):
        self.action_queue.append((self._do_copy_right_to_left, path))
    
    def _add_copy_time_left_to_right(self, path):
        self.action_queue.append((self._do_copy_time_left_to_right, path))
    
    def _add_copy_time_right_to_left(self, path):
        self.action_queue.append((self._do_copy_time_right_to_left, path))
    
    def _add_remove_left(self, path):
        self.action_queue.append((self._do_remove_left, path))
    
    def _add_remove_right(self, path):
        self.action_queue.append((self._do_remove_right, path))
    
    def _get_file_hash(self, fs, path):
        hash = self.hash_function()
        with fs.open(path) as file:
            data = file.read(1024*64)
            while data:            
                hash.update(data)
                data = file.read(1024*64)
        return hash.digest()

    def _get_modified_time(self, fs, path):
        info = fs.getinfo(path)
        if 'modified_time' in info:
            return info['modified_time']
        else:
            return None            

    def _add_sync_actions(self, path, check_time, check_content, ignore_patterns):
        pass

    def _add_mirror_actions(self, path, check_time, check_content, ignore_patterns):
        left_files = self.left_fs.listdir(path, full=True, files_only=True)
        
        for file in left_files:
            if self.right_fs.isfile(file):                
                if self.left_fs.getsize(file) != self.right_fs.getsize(file):
                    self._add_copy_left_to_right(file)
                elif check_time and self._get_modified_time(self.left_fs, file) != self._get_modified_time(self.right_fs, file):
                    self._add_copy_left_to_right(file)
                elif check_content and self._get_file_hash(self.left_fs, file) != self._get_file_hash(self.right_fs, file):
                    self._add_copy_left_to_right(file)
            else:
                if self.right_fs.isdir(file):
                    self._add_remove_right(file)
                self._add_copy_left_to_right(file)
                
        right_files = self.right_fs.listdir(path, full=True, files_only=True)
        #todo



def create_sync_job(left_fs, right_fs, check_time=True, check_content=False, ignore_patterns=[]):
    job = Job(left_fs, right_fs)
    job._add_sync_actions('/', '/', check_time, check_content, ignore_patterns)
    return job

def create_mirror_job(source_fs, mirror_fs, check_time=True, check_content=False, ignore_patterns=[]):
    job = Job(source_fs, mirror_fs)
    job._add_mirror_actions('/', '/', check_time, check_content, ignore_patterns)
    return job
